Welcome to Xceed DataGrid for Silverlight > Manipulating Data > Editing and Inserting Data |
The content of each cell in a grid—assuming that they are not read-only—can be edited programmatically or through end-user interactions at run time.
How and when the data in a grid can be edited is determined through combinations of the EditTriggers and CellEditorDisplayConditions properties, which state what triggers place a grid in edit mode and when the editors, which are used to edit cell content, are displayed, respectively. By default, the EditTriggers property is set to ClickOnCurrentCell, meaning that a grid will enter edit mode when the current cell is clicked, while the CellEditorDisplayConditions property is set to None, indicating that the current cell's editor will only be displayed when it is being edited. This combination of values results in a double-click action being necessary to edit the content of a cell.
Both the EditTriggers and CellEditorDisplayConditions properties support bitwise combinations of their member values and can be set on the grid or on a per-column basis.
Table 1: EditTriggers property values
Table 2: CellEditorDisplayConditions property values
The moment when the data is written to the underlying data source is determined by the value of a grid's UpdateSourceTrigger property, which indicates whether the source is updated when a cell or row is ending its edit process or when a cell's content is changed.
Through the BeginEdit, EndEdit, and CancelEdit methods, the edit process can be begun, ended, or canceled programmatically. When a grid's BeginEdit method is called, the current cell of the current item or of the specified data item will be put in edit mode. Calling EndEdit will attempt to end the edit process, while calling CancelEdit will cancel the edit process and revert any modified data back to its previous value.
If there is no current cell, the row will be put in edit mode; however, no cell will be immediately editable. |
The BeginEdit, EndEdit, and CancelEdit methods are also exposed by the EditableRow and EditableCell classes and their derivatives. Calling these methods on a row or cell will cause the calling row or cell to be put in edit mode. In the case where the BeginEdit method is called on a cell whose parent row is not in edit mode, the parent row will also be put in edit mode.
During the edit process, be it through end-user interactions or through programmatic editing, a series of events will be raised along the way to provide notifications as well as to allow custom behavior, such as committing modifications back to the data source, to be injected into the edit process. For example, the EditBeginning event will be raised when the BeginEdit method has been called to signal that the edit process is about to begin, while the EditBegun event will be raised after the EditBeginning event to signal that the edit process has begun. Similar events are also raised for the EndEdit and CancelEdit methods (see Table 3).
The edit events can be broken into 2 different types: those that are raised when interacting with a container (e.g., row) and those that are raised when interacting with an underlying source item (see Table 3). The order in which these events are raised depends on how and when the edit process was initiated. For example, if the edit process was initiated through end-user interaction, the EditBeginning event would be raised once for the row and then again for the cell, followed by the SourceItemEditBeginning and SourceItemEditBegun events, and ending with the EditBegun events raised for the cell and its parent row.
If there is no current cell, the appropriate edit events will be raised for the row; however, none will be raised for a cell. |
Table 3: Edit events
Because the container-based events can be raised by both cells and rows, it can be important to know which one raised the event. The ContainerType and Container properties, which are exposed by the DataGridEditEventArgs received in the event arguments, provide access to this information.
Through the InsertionRow, new items can be added to a grid. By default, an insertion row is not displayed; however, one can be added to the header or footer sections of grid (see Headers and Footers topic).
<sldg:DataGridControl.FixedHeaders> <sldg:InsertionRow/> </sldg:DataGridControl.FixedHeaders>
If the underlying data source implements the IEditableCollectionView interface, a new item will automatically be created and ready to be inserted when the insertion row is put in edit mode. If the underlying data source does not implement IEditableCollectionView, then the CreatingNewSourceItem event must be handled in order to provide the new data item to be inserted (see NewItem property) and its Handled property set to true to indicate that a new item was provided. In this event, or later in the NewSourceItemCreated event, the values in the data item that was created for the insertion row can be initialized. If the item was automatically created, it can be initialized in the NewSourceItemCreated event.
If the underlying data source does not implement IEditableCollectionView, a new item is not provided through the CreatingNewSourceItem event, and the e.Handled property is set to true, an InvalidOperationException will be thrown. |
<sldg:DataGridControl x:Name="sldgDataGridControl" ItemsSource="{Binding Path=Orders}" CreatingNewSourceItem="sldgDataGridControl_CreatingNewSourceItem"> <sldg:DataGridControl.FixedHeaders> <sldg:InsertionRow/> </sldg:DataGridControl.FixedHeaders> </sldg:DataGridControl>
Private Sub sldgDataGridControl_CreatingNewSourceItem( ByVal sender As Object, ByVal e As CreatingNewSourceItemEventArgs ) Dim order As New Order() order.Freight = 22 order.ShippedDate = DateTime.Today e.NewItem = order e.Handled = True End Sub
private void sldgDataGridControl_CreatingNewSourceItem( object sender, CreatingNewSourceItemEventArgs e ) { Order order = new Order(); order.Freight = 22; order.ShippedDate = DateTime.Today; e.NewItem = order; e.Handled = true; }
How and when changes are committed to the underlying data source depends on a variety of other factors, not the least of which is the asynchronicity of the data source. Ideally, modifications should be pushed to the underlying data source only when necessary, especially when dealing with a remote data source in order to prevent round-trips to the server. To that effect, having a "commit" button that saves the changes on demand is the recommended option; however, this may not always be the desired setup when, for example, many people are using the same data source and the modifications need to be propagated sooner rather than later. In this case, pushing the changes back to the data source when an item is edited or a new item is committed would be a better option and can be accomplished by handling the SourceItemEditEnded event and committing the changes back to the source.
Many data sources, such as WCF Data Services, provide asynchronous services to commit pending change sets back to the data source (e.g., DataServiceContext.BeginSaveChanges method). Although the recommended option is still to save the changes in the SourceItemEditEnded event, the fact that the operation is asynchronous adds a layer of complexity to the commit operation since the results, including any server-side validation, will not be known immediately. To allow for this scenario, the SourceItemEditEndedEventArgs, which is received in the event arguments, exposes a callback through the ResultCallback property, which will be called when the commit operation returns and should be provided to the asynchronous method that initiates the commit operation as the value of the state parameter. The HandlesResultCallback property, which is also received in the event arguments, indicates that the result callback will be handled and must be set to true in order for it to be called. In the asynchronous method's callback (not to be confused with the result callback received in the event arguments), the result callback can then be used to report any errors that occurred during the commit operation. Passing null (Nothing in Visual Basic) to the result callback indicates that the commit operation was successful.
NorthwindEntities is a DataServiceContext that was created by a WCF Data Services web service and that provides access to the required Northwind tables. Data refers to a static class that loads data from the DataServiceContext and exposes ObservableCollection<T> properties for non-virtualized tables and DataServiceQuery<T> properties for virtualized tables. |
Private Sub sldgDataGridControl_SourceItemEditEnded( ByVal sender As Object, ByVal e As SourceItemEditEndedEventArgs ) If e.IsNewItem Then ' inserting Data.NorthwindEntities.AddToOrders( CType( e.Item, Order ) ) End If Dim result As IAsyncResult = Data.NorthwindEntities.BeginSaveChanges( SaveChangesOptions.None, New AsyncCallback( AddressOf Me.SaveChanges ), e.ResultCallback ) e.HandlesResultCallback = Not result.IsCompleted If result.IsCompleted Then Data.NorthwindEntities.EndSaveChanges( result ) End If End Sub Private Sub SaveChanges( ByVal result As IAsyncResult ) If result.CompletedSynchronously Then Return End If Dim response As IAsyncResult = Data.NorthwindEntities.EndSaveChanges( result ) Dim delegateResult As SourceItemEditEndedDelegate = CType( result.AsyncState, SourceItemEditEndedDelegate ) Dim change As ChangeOperationResponse = CType( response.First(), ChangeOperationResponse ) delegateResult( change.Error ) End Sub
private void sldgDataGridControl_SourceItemEditEnded( object sender, SourceItemEditEndedEventArgs e ) { if( e.IsNewItem ) // inserting Data.NorthwindEntities.AddToOrders( e.Item as Order ); IAsyncResult result = Data.NorthwindEntities.BeginSaveChanges( SaveChangesOptions.None, new AsyncCallback( this.SaveChanges ), e.ResultCallback ); e.HandlesResultCallback = !result.IsCompleted; if( result.IsCompleted ) Data.NorthwindEntities.EndSaveChanges( result ); } private void SaveChanges( IAsyncResult result ) { if( result.CompletedSynchronously ) return; DataServiceResponse response = Data.NorthwindEntities.EndSaveChanges( result ); SourceItemEditEndedDelegate delegateResult = result.AsyncState as SourceItemEditEndedDelegate; ChangeOperationResponse change = response.First() as ChangeOperationResponse; delegateResult( change.Error ); }